# Copyright (c) 2019 Presto Labs Pte. Ltd.
# Author: taekwon

from coin.exchange.deribit_v1.kr_rest.currency import DeribitCurrency
from coin.exchange.deribit_v1.kr_rest.futures_product import DeribitFuturesProduct
from coin.proto.coin_query_pb2 import (AccountBalance,
                                       CurrencyBalance,
                                       AccountPosition,
                                       ProductPosition)


class DeribitFuturesPrivateParser(object):
  @staticmethod
  def parse_balance(update_msg):
    """
    {
        "jsonrpc": "2.0",
        "id": 2515,
        "result": {
            "available_funds": 5.00040249,
            "available_withdrawal_funds": 5.00040249,
            "balance": 5.00059399,
            "currency": "BTC",
            "delta_total": 0.0054,
            "deposit_address": "2N35qDKDY22zmJq9eSyiAerMD4enJ1xx6ax",
            "email": "user_AAA@email.com",
            "equity": 5.0005616,
            "futures_pl": -0.0000432,
            "futures_session_rpl": 0.00001081,
            "futures_session_upl": -0.0000432,
            "id": 2,
            "initial_margin": 0.00015911,
            "maintenance_margin": 0.00011597,
            "margin_balance": 5.0005616,
            "options_delta": 0,
            "options_gamma": 0,
            "options_pl": 0,
            "options_session_rpl": 0,
            "options_session_upl": 0,
            "options_theta": 0,
            "options_vega": 0,
            "portfolio_margining_enabled": false,
            "session_funding": 0,
            "session_rpl": 0.00001081,
            "session_upl": -0.0000432,
            "system_name": "user_1",
            "tfa_enabled": false,
            "total_pl": -0.0000432,
            "type": "main",
            "username": "user_1"
        }
    }
    """
    assert 'result' in update_msg
    currency_balance_list = []
    balance_info = update_msg['result']
    native_currency = balance_info['currency']
    currency = DeribitCurrency.FromStrNativeCurrency(native_currency)

    total = float(balance_info['margin_balance'])
    hold = float(balance_info['initial_margin'])
    available = float(balance_info['available_funds'])
    currency_balance = CurrencyBalance(currency=currency.currency,
                                       currency_native=currency.native_currency,
                                       total=total,
                                       hold=hold,
                                       available=available)
    currency_balance_list.append(currency_balance)

    return AccountBalance(
        exchange='Deribit',
        each_balance=currency_balance_list,
    )

  @staticmethod
  def parse_balance_total(update_msg_total):
    currency_balance_list = []
    for update_msg in update_msg_total:
      if update_msg.each_balance:
        currency_balance_list.append(update_msg.each_balance[0])
    return AccountBalance(
        exchange='Deribit',
        each_balance=currency_balance_list,
    )

  @staticmethod
  def parse_account_position(update_msg):
    """
    {
      "jsonrpc": "2.0",
      "id": 2236,
      "result": [
          {
              "average_price": 0,
              "delta": 0,
              "direction": "buy",
              "estimated_liquidation_price": 0,
              "floating_profit_loss": 0,
              "index_price": 3563.04,
              "initial_margin": 0,
              "instrument_name": "BTC-PERPETUAL",
              "kind": "future",
              "maintenance_margin": 0,
              "mark_price": 3579.63,
              "open_orders_margin": 0.000139733,
              "realized_profit_loss": 0,
              "settlement_price": 3561.74,
              "size_currency": 0,
              "size": 0,
              "total_profit_loss": 0
          }
      ]
    }
    """
    assert 'result' in update_msg
    product_positions = {}
    for pos_info in update_msg['result']:
      native_symbol = pos_info['instrument_name']
      product = DeribitFuturesProduct.FromStrNativeProduct(native_symbol)
      position = product_positions.get(native_symbol)
      if position is None:
        position = ProductPosition(symbol=product.symbol)
        product_positions[native_symbol] = position
      if pos_info['direction'] == 'buy':
        position.long_position = float(pos_info['size'])
      elif pos_info['direction'] == 'sell':
        position.short_position = float(pos_info['size'])
      elif pos_info['direction'] == 'zero':
        position.short_position = 0.
        position.long_position = 0.
      else:
        raise ValueError('Invalid direction! \n %s' % pos_info)

    for position in product_positions.values():
      position.net_position = position.long_position + position.short_position

    return AccountPosition(exchange='Deribit', each_position=product_positions.values())

  @staticmethod
  def parse_position_total(update_msg_total):
    position_list = []
    for update_msg in update_msg_total:
      if update_msg.each_position:
        position_list.append(update_msg.each_position[0])
    return AccountPosition(exchange='Deribit', each_position=position_list)
